#ifndef TD_TOWER_DEFENSE_H_
#define TD_TOWER_DEFENSE_H_


/************************************************************************/
/* CORE                                                                 */
/************************************************************************/
#include "Core/Color.h"
#include "Core/Timer.h"
#include "Core/Utils.h"

/************************************************************************/
/* Game                                                                 */
/************************************************************************/
#include "Game/Game Objects/Marios/BaseMario.h"
#include "Game/Tilemaps/TerrainTilemap.h"
#include "Game/Tilemaps/TurretTilemap.h"
#include "Game/Managers/TowerManager.h"
#include "Game/Managers/MarioManager.h"
#include "Game/Screen.h"
#include "Game/Managers/InputManager.h"
#include "Game/Game Objects/Cloud.h"
#include "Game/GameCore.h"
#include "Game/WaveInfo.h"

/************************************************************************/
/* RESOURCES                                                            */
/************************************************************************/
#include "Resources/Tiles/Tileset.h"
#include "Resources/SFX/SDLMusic.h"
#include "Resources/SFX/SDLSound.h"


/************************************************************************/
/* GUI                                                                  */
/************************************************************************/
#include "GUI/Panels/WaveInfoPanel.h"
#include "GUI/Panels/MenuPanel.h"
#include "GUI/TextMessages/TextMessage.h" 
#include "GUI/TextMessages/FadingMessage.h"
#include "GUI/Misc/Fadescreen.h"
#include "GUI/EntryScreen.h"
#include "GUI/GameOverScreen.h"
#include "GUI/Misc/Cursor.h"

using namespace TD_Core;
using namespace TD_Resources;
using namespace TD_GUI;

namespace TD_Game {

	
	class TowerDefense {
		
		/************************************************************************/
		/* Default definitions                                                  */
		/************************************************************************/
		const static unsigned int m_initialMoney;
		const static unsigned int m_initialLives;
		const static unsigned int m_statusFontSize;

		/************************************************************************/
		/* Game's system variables                                              */
		/************************************************************************/
		/**Timer and frame rate capping info*/
		Timer m_fpsTimer;
		Timer m_updateTimer;
		int m_numFrames;

		/** Rendering canvas info:*/
		Screen *m_pMainScreen;

		/** Game exiting variables the game.*/
		bool m_quit;
		bool m_gameStarted;
		bool m_gameWin;
		bool m_levelCreated;

		/************************************************************************/
		/* Sounds                                                               */
		/************************************************************************/
		/** Pre-allocated*/
		shared_ptr<SDLSound> m_pCoinSound;
		shared_ptr<SDLSound> m_pMarioPassed1;
		shared_ptr<SDLSound> m_pMarioPassed2;
		shared_ptr<SDLSound> m_pMarioPassed3;
		shared_ptr<SDLSound> m_pPauseSound;
		shared_ptr<SDLSound> m_pMarioHurry;
		shared_ptr<SDLSound> m_pPipeWarp;
		int m_musicIndex;
		deque<string> m_musicList;
		shared_ptr<SDLMusic> m_pBackgroundMusic;
		
		
		

		/************************************************************************/
		/* Graphical elements                                                   */
		/************************************************************************/
		Tileset m_terrainTileset;
		TerrainTilemap m_terrain;
		Coord2D m_terrainTilesize;
		/** Front of the Pipe image*/
		Tile *m_pPipeFront;
		
		/************************************************************************/
		/* GUI members                                                          */
		/************************************************************************/
		//Current creep id that is being showed by creep info panel
		unsigned int m_showingCreepID;

		/** Entry screen GUI component.*/
		EntryScreen *m_pEntryScreen;

		/** Game over screen.*/
		GameOverScreen *m_pGameOverScreen;
		shared_ptr<SDLSound> m_pGameoverSound;
		Timer m_gameOverTimer;

		/** Tower menu GUI */
		TowerMenuPanel *m_pTowerMenu;
		/** Tower info GUI*/
		bool m_showTowerInfo;
		TowerInfoPanel *m_pTowerInfo;
		/** Creep info GUI*/
		bool m_showCreepInfo;
		MarioInfoPanel *m_pCreepInfo;
		/** Creep bar GUI*/
		WaveInfoPanel *m_pWaveInfoPanel;
		/** Menu Panel GUI*/
		MenuPanel *m_pMenuPanel;
		/**Fadescreen*/
		Fadescreen *m_pFadescreen;

		/** User variables info:*/
		TextMessage *m_pLivesMsg;
		TextMessage *m_pMoneyMsg;
		TextMessage *m_pLevelMsg;
		TextMessage *m_pScoreMsg;
		FadingMessage *m_pWarningMsg;

		/************************************************************************/
		/* Game info                                                            */
		/************************************************************************/
		/** Waves: */
		vector<WaveInfo> m_waves;
		unsigned int m_currWave;
		
		/** Game status variables:*/
		int m_lives;
		int m_oldLives;
		unsigned int m_money;
		unsigned int m_score;
		int m_difficultySelected;
		
		/** Current game area.*/
		gameArea m_currGameArea;
		gameArea m_nextGameArea;

		/** Cloud that wanders around*/
		Cloud *m_pCloud;

		/************************************************************************/
		/* USER INTERACTION                                                     */
		/************************************************************************/
		/** Game input manager: handles all user interaction.*/
		InputManager *m_pInputManager;
		/** If the user is inserting a tower*/
		bool m_isInsertingTower;
		/** If the user does not have enough money or trying to insert a tower in an invalid position*/
		bool m_isInsertingInvalidTower;
		/** The inserting tower animation set.*/
		AnimationSet *m_pInsertTowerAS;
		/** The inserting invalid tower animation set.*/
		AnimationSet *m_pInsertInvalidTowerAS;
		/** The tower position for inserting*/
		Coord2D m_insertingTowerPosition;

		
		/************************************************************************/
		/* Private functions                                                    */
		/************************************************************************/
		
		/************************************************************************/
		/* Initialization                                                       */
		/************************************************************************/
		//Initialize the game system variables
		void initGameSystem();
		//Initialize the game graphical elements
		void initGraphicalElements();
		//Gui components
		void initGUI();
		//User interaction
		void initUserInteraction();

		/************************************************************************/
		/* Ingame                                                               */
		/************************************************************************/

		//Level creation: Instanciates the game objects in the level
		void createLevel();
		//Resources pre allocation
		void preallocateResources();

		
		/**Events:*/
		//Process user events in the game
		void processGameEvents();
		//Process pause events
		void processPauseEvents();
		
		/**Game loops:*/
		void processEntryScreen();
		void processGamePaused();
		void processGame();
		void processGameOver();
		
		/**Functionalities:*/
		void updateFrameRateCount();
		/** Restarts the game.*/
		void gameRestart();


		/************************************************************************/
		/* Rendering                                                            */
		/************************************************************************/
		
		//Renders the background scenario
		void renderScenario();
		//Renders the GUI elements
		void renderGUI();
		
	public:
		
		/************************************************************************/
		/* ctors and dtors                                                      */
		/************************************************************************/
		// Default
		TowerDefense();
		~TowerDefense();
			
	
		/************************************************************************/
		/* Functionalities                                                      */
		/************************************************************************/
		
		void setLevel(unsigned int level) {
			stringstream convertedInt;
			convertedInt << level;
			if(m_pLevelMsg == NULL) {
				m_pLevelMsg = new TextMessage(Coord2D(0.07714*screenWidth, 0.00719*screenHeight), convertedInt.str(), 
					"Fonts/SuperMarioAlphabet.TTF", m_statusFontSize, Color::WHITE);
			} else {
				m_pLevelMsg->setText(convertedInt.str());
			}
		}

		void setScore(unsigned int score) {
			m_score = score;
			stringstream convertedInt;
			convertedInt << m_score;

			if(m_pScoreMsg == NULL) {

				m_pScoreMsg = new TextMessage(Coord2D(0.194*screenWidth, 0.00719*screenHeight), convertedInt.str(), 
					"Fonts/SuperMarioAlphabet.TTF", m_statusFontSize, Color::WHITE);
			} else {
				m_pScoreMsg->setText(convertedInt.str());
			}
		}

		void setLives(unsigned int lives) {
			m_lives = lives;
			stringstream convertedInt;
			convertedInt << "x";
			convertedInt << m_lives;
			if(m_pLivesMsg == NULL) {
				m_pLivesMsg = new TextMessage(Coord2D(0.7076*screenWidth, 0.00719*screenHeight), convertedInt.str(), 
						"Fonts/SuperMarioAlphabet.TTF", m_statusFontSize, Color::WHITE);
			} else {
				m_pLivesMsg->setText(convertedInt.str());
			}
		}

		void setMoney(unsigned int money) {
			m_money = money;
			stringstream convertedInt;
			convertedInt << "x";
			convertedInt << m_money;
			if(m_pMoneyMsg == NULL) {
				m_pMoneyMsg = new TextMessage(Coord2D(0.5959*screenWidth, 0.00719*screenHeight), convertedInt.str(), 
					"Fonts/SuperMarioAlphabet.TTF", m_statusFontSize, Color::WHITE);
			} else {
				m_pMoneyMsg->setText(convertedInt.str());
			}
		}

		void setWarningMsg(const string &warningMsg) {
			Color warningColor(255, 0, 0, 255); 
			if(m_pWarningMsg == NULL) {
				m_pWarningMsg = new FadingMessage(Coord2D(0.2914*screenWidth, 0.40625*screenHeight), warningMsg, 
					"Fonts/SuperMarioAlphabet.TTF", 40
					, warningColor);
			} else {
				m_pWarningMsg->resetFading();
				Coord2D offset(325, 325);
				offset.x -= 6 * (warningMsg.size() - 20);
				m_pWarningMsg->setPosition(offset);
				m_pWarningMsg->setText(warningMsg);
			}
		}

		
		// Process the game main loop
		void process();

		


		bool hasGameEnded() {
			return(m_quit);
		}

	};
}
#endif